package com.zwb.game.core.classloader;

import java.io.*;
import java.util.HashMap;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;

/**
 * jar包加载器
 * Create by zwb on 2020-01-18 15:50
 */
public class JarClassLoader extends ClassLoader {
    private String path;

    private final Map<String, byte[]> datas = new HashMap<String, byte[]>();

    private final Map<String, Class> classes = new HashMap<String, Class>();

    public JarClassLoader(String jarPath) throws IOException {
        this.loadJar(jarPath);
        for (String s : this.datas.keySet()) {
            if (s.endsWith(".class")) {
                String className = convertToClassName(s);
                if (!this.classes.containsKey(className)) {
                    this.defineClass(className);
                }
            }
        }
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        Class clazz = this.classes.get(name);
        if (clazz == null) {
            clazz = this.defineClass(name);
        }
        return clazz == null ? super.findClass(name) : clazz;
    }

    private Class<?> defineClass(String className) {
        byte[] bytes = this.datas.get(className);
        if (bytes == null) {
            return null;
        } else {
            Class<?> clazz = this.defineClass(className, bytes, 0, bytes.length);
            if (clazz.getPackage() == null) {

            }
            this.classes.put(className, clazz);
            return clazz;
        }
    }

    private String convertToClassName(String s) {
        return null;
    }

    private void loadJar(String jarPath) throws IOException {
        FileInputStream fis = null;
        try {
            File file = new File(jarPath);
            this.path = file.getAbsolutePath();
            fis = new FileInputStream(file);
            this.loadJar(fis);
        } catch (FileNotFoundException e) {
            throw e;
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    throw e;
                }
            }
        }
    }

    public void loadJar(InputStream jarStream) {
        BufferedInputStream bis = null;
        JarInputStream jis = null;
        try {
            bis = new BufferedInputStream(jarStream);
            jis = new JarInputStream(bis);

            JarEntry jarEntry = null;

            for (jarEntry = jis.getNextJarEntry(); jarEntry != null; ) {
                if (jarEntry.isDirectory()) {
                    continue;
                }
                if (datas.containsKey(jarEntry.getName())) {
                    continue;
                }
                ByteArrayOutputStream out = new ByteArrayOutputStream();
                byte[] b = new byte[2048];
                int len;
                while ((len = jis.read(b)) > 0) {
                    out.write(b, 0, len);
                }
                this.datas.put(jarEntry.getName(), out.toByteArray());
                out.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (jis != null) {
                try {
                    jis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (bis != null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
